package repository

import (
	"context"
	"fmt"

	"github.com/devops-smartbot/devops-smartbot/services/integration-service/internal/models"
	"go.mongodb.org/mongo-driver/bson"
	"go.mongodb.org/mongo-driver/mongo"
	"go.mongodb.org/mongo-driver/mongo/options"
)

type IntegrationRepository struct {
	db                      *mongo.Database
	jiraConfigColl          *mongo.Collection
	pagerdutyConfigColl     *mongo.Collection
	ticketJiraMappingColl   *mongo.Collection
	alertPagerDutyMappingColl *mongo.Collection
}

func NewIntegrationRepository(db *mongo.Database) *IntegrationRepository {
	return &IntegrationRepository{
		db:                      db,
		jiraConfigColl:          db.Collection("jira_configs"),
		pagerdutyConfigColl:     db.Collection("pagerduty_configs"),
		ticketJiraMappingColl:   db.Collection("ticket_jira_mappings"),
		alertPagerDutyMappingColl: db.Collection("alert_pagerduty_mappings"),
	}
}

// Jira Config Methods
func (r *IntegrationRepository) GetJiraConfig(ctx context.Context) (*models.JiraConfig, error) {
	var config models.JiraConfig
	err := r.jiraConfigColl.FindOne(ctx, bson.M{}).Decode(&config)
	if err == mongo.ErrNoDocuments {
		return nil, nil
	}
	if err != nil {
		return nil, fmt.Errorf("failed to get jira config: %w", err)
	}
	return &config, nil
}

func (r *IntegrationRepository) UpsertJiraConfig(ctx context.Context, config *models.JiraConfig) error {
	upsert := true
	opts := &options.UpdateOptions{Upsert: &upsert}

	filter := bson.M{}
	update := bson.M{
		"$set": config,
	}

	_, err := r.jiraConfigColl.UpdateOne(ctx, filter, update, opts)
	if err != nil {
		return fmt.Errorf("failed to upsert jira config: %w", err)
	}
	return nil
}

// PagerDuty Config Methods
func (r *IntegrationRepository) GetPagerDutyConfig(ctx context.Context) (*models.PagerDutyConfig, error) {
	var config models.PagerDutyConfig
	err := r.pagerdutyConfigColl.FindOne(ctx, bson.M{}).Decode(&config)
	if err == mongo.ErrNoDocuments {
		return nil, nil
	}
	if err != nil {
		return nil, fmt.Errorf("failed to get pagerduty config: %w", err)
	}
	return &config, nil
}

func (r *IntegrationRepository) UpsertPagerDutyConfig(ctx context.Context, config *models.PagerDutyConfig) error {
	upsert := true
	opts := &options.UpdateOptions{Upsert: &upsert}

	filter := bson.M{}
	update := bson.M{
		"$set": config,
	}

	_, err := r.pagerdutyConfigColl.UpdateOne(ctx, filter, update, opts)
	if err != nil {
		return fmt.Errorf("failed to upsert pagerduty config: %w", err)
	}
	return nil
}

// Ticket-Jira Mapping Methods
func (r *IntegrationRepository) CreateTicketJiraMapping(ctx context.Context, mapping *models.TicketJiraMapping) error {
	_, err := r.ticketJiraMappingColl.InsertOne(ctx, mapping)
	if err != nil {
		return fmt.Errorf("failed to create ticket jira mapping: %w", err)
	}
	return nil
}

func (r *IntegrationRepository) GetTicketJiraMapping(ctx context.Context, ticketID string) (*models.TicketJiraMapping, error) {
	var mapping models.TicketJiraMapping
	err := r.ticketJiraMappingColl.FindOne(ctx, bson.M{"ticket_id": ticketID}).Decode(&mapping)
	if err == mongo.ErrNoDocuments {
		return nil, nil
	}
	if err != nil {
		return nil, fmt.Errorf("failed to get ticket jira mapping: %w", err)
	}
	return &mapping, nil
}

func (r *IntegrationRepository) GetJiraTicketMapping(ctx context.Context, jiraKey string) (*models.TicketJiraMapping, error) {
	var mapping models.TicketJiraMapping
	err := r.ticketJiraMappingColl.FindOne(ctx, bson.M{"jira_key": jiraKey}).Decode(&mapping)
	if err == mongo.ErrNoDocuments {
		return nil, nil
	}
	if err != nil {
		return nil, fmt.Errorf("failed to get jira ticket mapping: %w", err)
	}
	return &mapping, nil
}

// Alert-PagerDuty Mapping Methods
func (r *IntegrationRepository) CreateAlertPagerDutyMapping(ctx context.Context, mapping *models.AlertPagerDutyMapping) error {
	_, err := r.alertPagerDutyMappingColl.InsertOne(ctx, mapping)
	if err != nil {
		return fmt.Errorf("failed to create alert pagerduty mapping: %w", err)
	}
	return nil
}

func (r *IntegrationRepository) GetAlertPagerDutyMapping(ctx context.Context, alertID string) (*models.AlertPagerDutyMapping, error) {
	var mapping models.AlertPagerDutyMapping
	err := r.alertPagerDutyMappingColl.FindOne(ctx, bson.M{"alert_id": alertID}).Decode(&mapping)
	if err == mongo.ErrNoDocuments {
		return nil, nil
	}
	if err != nil {
		return nil, fmt.Errorf("failed to get alert pagerduty mapping: %w", err)
	}
	return &mapping, nil
}

func (r *IntegrationRepository) GetPagerDutyAlertMapping(ctx context.Context, incidentID string) (*models.AlertPagerDutyMapping, error) {
	var mapping models.AlertPagerDutyMapping
	err := r.alertPagerDutyMappingColl.FindOne(ctx, bson.M{"incident_id": incidentID}).Decode(&mapping)
	if err == mongo.ErrNoDocuments {
		return nil, nil
	}
	if err != nil {
		return nil, fmt.Errorf("failed to get pagerduty alert mapping: %w", err)
	}
	return &mapping, nil
}
